/*
 *    This file is part of CeluMap.
 *
 *    CeluMap is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    CeluMap is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Copyright 2006, 2007, 2008 Gonzalo Merayo
 *    gonzalo (at) celumap.com.ar
 *    www.celumap.com.ar
 *
 */

package screen;

import figures.Colors;
import geometry.Rectangle;
import image.GisImage;

import javax.microedition.lcdui.Graphics;

public class DrawingScreenBuffer implements GisGraphics{
	protected static byte[] buff = null;
	protected static Rectangle area = null;
	protected static int w;
	protected static int h;
	
	protected static byte c = 0x00;
	protected static int thickness = 1;
	
	public int getWidth(){
		return w;
	}
	public int getHeight(){
		return h;
	}
	public void setClip(Rectangle a){
		area =a;
	}
	public void setColor(byte color) {
		c = color;
	}
	public DrawingScreenBuffer(int width,int height){
		w = width;
		h = height;
		buff = new byte[width*height];
	}
	
	public void clear(Rectangle area) {
		int y = area.bbyi*w;
		for(int x=area.bbxi;x<area.bbxf;x++)
			buff[x + y] = Colors.background;
		for(y=area.bbyi+1;y<area.bbyf;y++)
			System.arraycopy(buff, area.bbxi + area.bbyi*w, buff, area.bbxi + y*w, area.bbxf-area.bbxi);
	}
	
	static int[] line = null;
	static int[] palette = Colors.palette;
	public void paint(Graphics gr){
		if(line==null)
			line = new int[w];
		for(int j=0;j<h;j++){
			for(int i=0;i<w;i++)
				line[i] = palette[buff[i + j*w]];
			gr.drawRGB(line, 0, w, 0, j, w, 1, false);
		}
	}

	static int temp, slope, d,incrHV,incrH;;
    public void drawLine (int x1, int y1, int x2, int y2)
	{
      int dx = x2 - x1;
      int dy = y2 - y1;
      if (dx == 0)
      {
        if(y1 < y2){
          for(int yv=y1;yv<y2;yv++)
        	  if(x1 >= area.bbxi && yv >= area.bbyi && x1<area.bbxf && yv<area.bbyf)
        		  buff[x1 + yv*w] = c;
        }else{
	      for(int yv=y2;yv<y1;yv++)
	    	  if(x1 >= area.bbxi && yv >= area.bbyi && x1<area.bbxf && yv<area.bbyf)
	    		  buff[x1 + yv*w] = c;
        }  
      }
	  else if (dy == 0)
	  {
	    if (x1 < x2){
			for(int xh=x1;xh<x2;xh++)
				if(xh >= area.bbxi && y1 >= area.bbyi && xh<area.bbxf && y1<area.bbyf)
					buff[xh + y1*w] = c;
	    }else{
			for(int xh=x2;xh<x1;xh++)
				if(xh >= area.bbxi && y1 >= area.bbyi && xh<area.bbxf && y1<area.bbyf)
					buff[xh + y1*w] = c;
	    }
	  }
	  else
	  {
	    // From Bresenham's line generation algorithm
	    // v1.1 : suppressed all float use
	    boolean swapXY = false;
	    if (dy*dy > dx*dx)
	    {
	      temp = x1;
	      x1 = y1;
	      y1 = temp;
	      temp = x2;
	      x2 = y2;
	      y2 = temp;
	      swapXY = true;
	    }
        if (x1 > x2)
        {
	      temp = x1;
	      x1 = x2;
	      x2 = temp;
	      temp = y1;
	      y1 = y2;
	      y2 = temp;
	    }
        dx = x2 - x1;
	    dy = y2 - y1;
        if (dy * dx < 0)
        {
          if (dy < 0){
        	incrH  = -2 * dy;
        	d      = incrH - dx;
            incrHV = d - dx;
          }else{
        	incrH  = 2 * dy;
        	d      = incrH +dx;
            incrHV = d + dx;
          }
          slope = -1;
	    }else{
	      incrH  = 2*dy;
	      d      = incrH - dx;
	      incrHV = d-dx;
	      slope = 1;
	    }
        if (swapXY){
        	if(x2>=area.bbyf)
        		x2=area.bbyf-1;
        	for(;x1<area.bbyi;x1++)
		    {
		      if(d <= 0)
		    	  d +=incrH;
		      else{
			      d +=incrHV; 
			      y1 +=slope;
		      }
		    }
        	for(;x1<=x2;x1++)
		    {
        	  if(y1 >= area.bbxi && y1<area.bbxf)
        		buff[y1 + x1*w] = c;
		      if(d <= 0)
		    	  d +=incrH;
		      else{
			      d +=incrHV; 
			      y1 +=slope;
		      }
		    }
        }else{
        	if(x2>=area.bbxf)
        		x2=area.bbxf-1;
        	for(;x1<area.bbxi;x1++){
				if(d <= 0)
					d +=incrH;
				else{
					d +=incrHV; 
					y1 +=slope;
				}
        	}
        	for(;x1<=x2;x1++)
		    {
    		  if(y1 >= area.bbyi && y1<area.bbyf)
    			buff[x1 + y1*w] = c;
		      if(d <= 0)
		    	  d +=incrH;
		      else{
			      d +=incrHV; 
			      y1 +=slope;
		      }
		    }
        }
      }
	}

	public void setThickness(int t) {
		thickness = t;
	}
	
	static int[] inters = new int[30];
	static int bxi, bxf, bxt, yf, yi, k;
	public void fill(int[] sx, int[] sy, int l) {
		if(inters.length<l)
			inters=new int[l];
		bxi = sx[0];
		bxf = sx[0];
		for(int i=1;i<l;i++){
			bxt = sx[i];
			if(bxi>bxt) bxi=bxt;
			if(bxf<bxt) bxf=bxt;
		}
		if(bxf>area.bbxf) bxf=area.bbxf;
		if(bxi<area.bbxi) bxi=area.bbxi;
		if(bxi<0)
			bxi=0;
		for(;bxi<bxf;bxi++){
			getIntersections(bxi, sx, sy, l);
			for(k=0;k<j;k+=2){
				yf = inters[k+1];
				yi = inters[k];
				if(yf<area.bbyi)
					continue;
				if(yi>area.bbyf)
					break;
				if(yf>area.bbyf)
					yf=area.bbyf*w + bxi;
				else
					yf = yf*w + bxi;
				if(yi<area.bbyi)
					yi = area.bbyi*w + bxi;
				else
					yi = yi*w + bxi;
				for(;yi<yf;yi+=w)
		    		buff[yi] = c;
			}
		}
		
	}
	static int mid, right, ay, by,ax, bx,y,p,left, j;
	private static final void getIntersections(int xs, int[] sx, int[] sy, int l) {
		j=0;
		ax = sx[l-1];
		ay = sy[l-1];
		for(int i=0;i<l;i++){
			bx = sx[i];
			by = sy[i];
			if((ax<=xs || bx<=xs) && (ax>xs|| bx>xs)){
				if(bx!=xs)
					y = ((xs-bx)*(ay-by))/(ax-bx)+by;
				else
					y = by;
				left = 0;
				switch(++j){
					case 1:
						break;
					case 2:
						if(y>inters[0])
							left = 1;
						else
							inters[1]=inters[0];
						break;
					case 3:
						if(y>inters[1])
							left = 2;
						else{
							inters[2]=inters[1];
							if(y>inters[0])
								left = 1;
							else
								inters[1]=inters[0];
						}
						break;
					default:
						right = j-2;
						while(left<=right){
					        mid=(left+right)/2;
					        if(y>inters[mid])
					            left=mid+1;
					        else{
					        	if(y<inters[mid])
					        		right=mid-1;
					        	else{
					        		left=mid;
					        		break;
					        	}
					        }
						}
						System.arraycopy(inters, left, inters, left+1, j-left);
				}
				inters[left]=y;
			}else{
				
			}
			ax = bx;
			ay = by;
		}
	}
	
	public void image(GisImage im, int xi, int yi, int j) {
		int oxi = xi<0?-xi:0;
		if(oxi>im.getWidth())
			return;
		if(xi > w || yi > h)
			return;
		int yf = im.getHeight();
		if(yf > h-yi)
			yf = h-yi;
		for(int y = yi<0?-yi:0;y < yf;y++){
			System.arraycopy(im.getBuff(), im.getXInitOff()+oxi+(y+im.getYInitOff())*im.getXoff(),
					         buff, oxi+xi+(y+yi)*w,
					         Math.min(im.getWidth()-oxi,w-xi-oxi));
			/*int aini = im.getXInitOff()+oxi+(y+im.getYInitOff())*im.getXoff();
			int bini = oxi+xi+(y+yi)*w;
			int len = Math.min(im.getWidth()-oxi,w-xi-oxi);
			int c = 0;
			for(int i=0;i<len;i++){
				c = im.getBuff()[i+aini];
				if((c&0x00FFFFFF)!=0xFFFFFF)
					buff[i+bini]=c;
			}
			*/
		}
	}
	public void drawString(byte[] str, int x, int y, int dx, int dy) {
		// TODO Auto-generated method stub
		
	}
}